package hub

import (
	"sync"
)

type Conn interface {
	WriteData(data []byte)
	GetId() uint64
	GetLastTime() int64
	Server() Server
	IP() string
	Close()
}

type Server interface {
	GetHub() ConHub
}

type ConHub interface {
	Size() int
	AddCon(conn Conn)
	GetCon(id uint64) Conn
	DelCon(id uint64)
	Contains(id uint64) bool
	BroadcastMessage(data []byte)
	ForEachConnection(f func(conn Conn))
	GetRandomClient() Conn
}

type DefaultConHub struct {
	hub   map[uint64]Conn
	mutex *sync.RWMutex
}

func NewHub() *DefaultConHub {
	hub := DefaultConHub{
		hub:   make(map[uint64]Conn),
		mutex: &sync.RWMutex{},
	}
	return &hub
}

func (this *DefaultConHub) Size() int {
	this.mutex.RLock()
	defer this.mutex.RUnlock()
	return len(this.hub)
}

func (this *DefaultConHub) AddCon(conn Conn) {
	this.mutex.Lock()
	defer this.mutex.Unlock()
	this.hub[conn.GetId()] = conn
}

func (this *DefaultConHub) GetCon(id uint64) Conn {
	this.mutex.RLock()
	defer this.mutex.RUnlock()
	return this.hub[id]
}

func (this *DefaultConHub) DelCon(id uint64) {
	this.mutex.Lock()
	defer this.mutex.Unlock()
	if _, ok := this.hub[id]; ok {
		delete(this.hub, id)
	}
}

func (this *DefaultConHub) Contains(id uint64) bool {
	this.mutex.RLock()
	defer this.mutex.RUnlock()
	_, ok := this.hub[id]
	return ok
}

func (this *DefaultConHub) BroadcastMessage(data []byte) {
	this.mutex.RLock()
	defer this.mutex.RUnlock()
	for _, v := range this.hub {
		v.WriteData(data)
	}
}

func (this *DefaultConHub) ForEachConnection(f func(conn Conn)) {
	this.mutex.RLock()
	defer this.mutex.RUnlock()
	for _, v := range this.hub {
		f(v)
	}
}
